/*
 * Copyright (C) 2011 The Android Open Source Project Licensed under the Apache
 * License, Version 2.0 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
 * or agreed to in writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */

package com.way.selectcontact.util;

import android.content.Context;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.style.ForegroundColorSpan;
import android.util.TypedValue;
import android.widget.TextView;

/**
 * Highlights the text in a text field.
 */
public class PrefixHighlighter {

	/* Color used when highlighting the prefixes */
	private final int mPrefixHighlightColor;

	private ForegroundColorSpan mPrefixColorSpan;

	/**
	 * @param prefixHighlightColor
	 *            The color used to highlight the prefixes.
	 */
	public PrefixHighlighter(final Context context) {
		mPrefixHighlightColor = context.getResources().getColor(
				getResIdFromAttribute(context,
						android.support.v7.appcompat.R.attr.colorAccent));
	}

	public static int getResIdFromAttribute(final Context context,
			final int attr) {
		if (attr == 0)
			return 0;
		final TypedValue typedValue = new TypedValue();
		context.getTheme().resolveAttribute(attr, typedValue, true);
		return typedValue.resourceId;
	}

	/**
	 * Sets the text on the given {@link TextView}, highlighting the word that
	 * matches the given prefix.
	 * 
	 * @param view
	 *            The {@link TextView} on which to set the text
	 * @param text
	 *            The string to use as the text
	 * @param prefix
	 *            The prefix to look for
	 */
	public void setText(final TextView view, final String text,
			final char[] prefix) {
		if (view == null || TextUtils.isEmpty(text) || prefix == null
				|| prefix.length == 0) {
			return;
		}
		view.setText(apply(text, prefix));
	}

	/**
	 * Returns a {@link CharSequence} which highlights the given prefix if found
	 * in the given text.
	 * 
	 * @param text
	 *            the text to which to apply the highlight
	 * @param prefix
	 *            the prefix to look for
	 */
	public CharSequence apply(final CharSequence text, final char[] prefix) {
		int mIndex = indexOfPrefix(text, prefix, true);
		// prefer word prefix, if not search through the entire word
		if (mIndex == -1) {
			mIndex = indexOfPrefix(text, prefix, false);
		}

		if (mIndex != -1) {
			if (mPrefixColorSpan == null) {
				mPrefixColorSpan = new ForegroundColorSpan(
						mPrefixHighlightColor);
			}
			final SpannableString mResult = new SpannableString(text);
			mResult.setSpan(mPrefixColorSpan, mIndex, mIndex + prefix.length, 0);
			return mResult;
		} else {
			return text;
		}
	}

	/**
	 * Finds the index of the first character that starts with the given prefix.
	 * If not found, returns -1.
	 * 
	 * @param text
	 *            the text in which to search for the prefix
	 * @param prefix
	 *            the text to find, in upper case letters
	 * @param wordOnly
	 *            only search for word prefixes if true
	 */
	private int indexOfPrefix(final CharSequence text, final char[] prefix,
			boolean wordOnly) {
		if (TextUtils.isEmpty(text) || prefix == null) {
			return -1;
		}

		final int mTextLength = text.length();
		final int mPrefixLength = prefix.length;

		if (mPrefixLength == 0 || mTextLength < mPrefixLength) {
			return -1;
		}

		int i = 0;
		while (i < mTextLength) {
			/* Skip non-word characters */
			while (i < mTextLength
					&& !Character.isLetterOrDigit(text.charAt(i))) {
				i++;
			}

			if (i + mPrefixLength > mTextLength) {
				return -1;
			}

			/* Compare the prefixes */
			int j;
			for (j = 0; j < mPrefixLength; j++) {
				if (Character.toUpperCase(text.charAt(i + j)) != prefix[j]) {
					break;
				}
			}
			if (j == mPrefixLength) {
				return i;
			}

			if (wordOnly) {
				/* Skip this word */
				while (i < mTextLength
						&& Character.isLetterOrDigit(text.charAt(i))) {
					i++;
				}
			} else {
				i++;
			}
		}
		return -1;
	}
}
